package org.acghub.common.topology;

import lombok.Getter;

import java.util.List;
import java.util.StringJoiner;
import java.util.function.Function;

/**
 * 环路检测器
 */
public interface CircleFinder<T> {

    /**
     * 添加边
     *
     * @param from
     * @param to
     */
    void addEdge(T from, T to);

    /**
     * 删除边
     */
    boolean removeEdge(T from, T to);

    /**
     * 检查是否有环
     *
     * @return
     */

    FindCircleResp<T> findCircle();

    @Getter
    enum VisitState {

        // 表示该节点尚未被访问
        WHITE(0),

        // 表示该节点正在被访问, 但其所有邻接节点尚未完全遍历完
        GRAY(1),

        // 表示该节点及其所有邻接节点都已被完全访问。
        BLACK(2),

        ;
        private final int state;

        VisitState(int state) {
            this.state = state;
        }
    }

    class FindCircleResp<T> {
        List<T> circle;

        FindCircleResp(List<T> circle) {
            this.circle = circle;
        }

        public boolean hasCircle() {
            return circle != null && !circle.isEmpty();
        }

        public <U> String getCircleStr(Function<T, U> converter) {
            StringJoiner joiner = new StringJoiner(" -> ");
            if (hasCircle()) {
                for (T t : circle) {
                    joiner.add(String.valueOf(converter.apply(t)));
                }
            }
            return joiner.toString();
        }

        public String getCircleStr() {
            return getCircleStr(Function.identity());
        }

        public <U> void throwIfCircle(Function<T, U> converter) {
            if (hasCircle()) {
                throw new TopologyCircleException("Circle found: " + getCircleStr(converter));
            }
        }

        public void throwIfCircle() {
            if (hasCircle()) {
                throw new TopologyCircleException("Circle found: " + getCircleStr());
            }
        }
    }

}
